package consulx

import (
	"common/configx"
	"fmt"
	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/go-cleanhttp"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	healthpb "google.golang.org/grpc/health/grpc_health_v1"
)

type ConsulX struct {
	*api.Client
	Service *ConsulAgentService
}

type ConsulAgentService struct {
	ServiceName string
	Port        int
	Ip          string
	Check       *healthCheckConfig
}

type healthCheckConfig struct {
	timeOut                        string //超时时间
	interval                       string //运行检查的频率
	deregisterCriticalServiceAfter string //自动注销时间
}

type ConsulXOpt func(c *ConsulX)

// NewConsulX 新建 consul 客户端
func NewConsulX(opts ...ConsulXOpt) *ConsulX {
	c := &ConsulX{}
	for _, opt := range opts {
		opt(c)
	}
	return c
}

// WithRegisterServer 配置注册的服务
func WithRegisterServer(name, ip string, port int) ConsulXOpt {
	return func(c *ConsulX) {
		c.Service = &ConsulAgentService{
			ServiceName: name,
			Port:        port,
			Ip:          ip,
		}
	}
}

// WithDefaultHealth 默认的健康检查配置
func WithDefaultHealth() ConsulXOpt {
	return func(c *ConsulX) {
		c.Service.Check = &healthCheckConfig{
			timeOut:                        "10s",
			interval:                       "10s",
			deregisterCriticalServiceAfter: "1m",
		}
	}
}

// RegisterHealth 注册健康检查处理逻辑到 grpc 里
func RegisterHealth(service *grpc.Server) {
	healthCheck := health.NewServer()
	healthpb.RegisterHealthServer(service, healthCheck)
}

// RegisterService 注册服务
func (c *ConsulX) RegisterService(tags []string) error {
	agentServiceRegistration := &api.AgentServiceRegistration{
		ID:      fmt.Sprintf("%s-%s-%d", c.Service.ServiceName, c.Service.Ip, c.Service.Port), // 服务唯一ID
		Name:    c.Service.ServiceName,                                                        // 服务名称
		Tags:    tags,                                                                         // 为服务打标签
		Address: c.Service.Ip,
		Port:    c.Service.Port,
	}
	if c.Service.Check != nil {
		agentServiceRegistration.Check = &api.AgentServiceCheck{
			GRPC:                           fmt.Sprintf("%s:%d", c.Service.Ip, c.Service.Port),
			Timeout:                        c.Service.Check.timeOut,
			Interval:                       c.Service.Check.interval,
			DeregisterCriticalServiceAfter: c.Service.Check.deregisterCriticalServiceAfter,
		}
	}
	return c.Client.Agent().ServiceRegister(agentServiceRegistration)
}

func (c *ConsulX) Connect() error {
	ac, err := api.NewClient(&api.Config{
		Scheme:    "http",
		Address:   fmt.Sprintf("%s:%d", configx.C.Consul.Address, configx.C.Consul.Port),
		Transport: cleanhttp.DefaultPooledTransport(),
	})
	if err != nil {
		return err
	}
	c.Client = ac
	return nil
}

func (c *ConsulX) Shutdown() error {

	return nil
}
